package com.moyq5.permit.center.web;

import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.type.TypeReference;
import com.moyq5.mvc.framework.encrypt.AES;
import com.moyq5.mvc.framework.encrypt.HEX;
import com.moyq5.mvc.framework.encrypt.JSON;
import com.moyq5.mvc.framework.encrypt.MD5;
import com.moyq5.mvc.framework.general.Body;
import com.moyq5.mvc.framework.general.Sorting;
import com.moyq5.mvc.framework.jackson.result.ObjectResult;
import com.moyq5.mvc.framework.jackson.result.StatusResult.Status;
import com.moyq5.mvc.framework.utils.StringUtils;
import com.moyq5.permit.center.bean.entity.SysAdmin;
import com.moyq5.permit.center.bean.search.SysAdmin4Search;
import com.moyq5.permit.center.feign.client.SysAdminFeign;

/**
 * 授权码Realm
 * @author Moyq5
 * @date 2019年8月13日
 */
@Component
public class ShiroCodeRealm extends ShiroRealm {
	private static final Logger log = LoggerFactory.getLogger(ShiroCodeRealm.class);
	
	@Autowired
	private SysAdminFeign adminFeign;
	
	@Override
	protected SysAdmin doGetAdminInfo(AuthenticationToken token) {
		final String message = "授权失败";
		final String name = (String)token.getPrincipal();
		final String code = (String)token.getCredentials();
		if (StringUtils.isEmpty(name) || StringUtils.isEmpty(code)) {
			log.debug("用户名和授权码参数为空");
			throw new AuthenticationException(message);
		}
		SysAdmin4Search admin4s = new SysAdmin4Search();
		admin4s.setName(name);
		ObjectResult<SysAdmin> adminRst = adminFeign.one(new Body<SysAdmin4Search, Sorting>(admin4s, new Sorting()));
		if (adminRst.getStatus() != Status.OK) {
			throw new AuthenticationException(adminRst.getMessage());
		}
		SysAdmin admin;
		if (null == (admin = adminRst.getData())) {
			log.debug("账号不存在：{}", name);
			throw new AuthenticationException(message);
		}
		String json;
		try {
			byte[] data = AES.decrypt(Base64.getUrlDecoder().decode(code), HEX.toByteArray(admin.getPwd()));
			json = new String(data, "UTF-8");
		} catch (Exception e) {
			log.error("授权码解密异常", e);
			throw new AuthenticationException(message);
		}
		Map<String, String> map = JSON.toObject(json, new TypeReference<TreeMap<String, String>>() {});
		String timestamp = map.get("timestamp");
		if (null == timestamp) {
			log.debug("请求参数无效：timestamp=null");
			throw new AuthenticationException(message);
		} else if (Long.parseLong(timestamp) + 20000 < System.currentTimeMillis()) {// 20秒内有效
			log.debug("请求已过期：timestamp={}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(Long.parseLong(timestamp))));
			throw new AuthenticationException(message);
		}
		String sign = map.get("sign");
		map.remove("sign");
		StringBuffer sb = new StringBuffer();
		map.forEach((key, value) -> {
			sb.append(key + "=" + value + "&");
		});
		sb.append("key=" + admin.getPwd());
		if (!sign.equalsIgnoreCase(MD5.encrypt2Hex(sb.toString()))) {
			log.debug("请求签名有误");
			throw new AuthenticationException(message);
		}
		return admin;
	}
	
	@Override
	public Class<?> getAuthenticationTokenClass() {
		return ShiroCodeToken.class;
	}

}
